package com.joshondesign.sdljava.gfx;

import com.joshondesign.sdljava.*;

public abstract class GFX {
    SDL_Surface surface;
    private SDL_Rect fillRect_rect;
    private SDL_Rect imgsrc_rect;
    private SDL_Rect imgdst_rect;
    private SDL_Rect fontsrc_rect;
    private SDL_Rect fontdst_rect;
    protected SDL_PixelFormat format;
    protected int translateX;
    protected int translateY;
    protected SPaint currentPaint = SColor.BLACK;
    protected SColor currentColor = SColor.BLACK;
    protected long current_sdlcolor = SColor.BLACK._sdlcolor;
    protected Bounds clipRect;

    public GFX(SDL_Surface surface) {
        this.surface = surface;
        this.format = surface.getFormat();
        this.fillRect_rect = new SDL_Rect();
        this.imgsrc_rect = new SDL_Rect();
        this.imgdst_rect = new SDL_Rect();
        this.fontsrc_rect = new SDL_Rect();
        this.fontdst_rect = new SDL_Rect();

        SDL_Rect r1 = new SDL_Rect();
        SDL.SDL_GetClipRect(surface,r1);
        this.clipRect = new Bounds(r1);

    }

    public void dispose() {
        fillRect_rect.delete();
        imgsrc_rect.delete();
        imgdst_rect.delete();
        fontsrc_rect.delete();
        fontdst_rect.delete();
        format.delete();
    }

    public void fillRect(int x, int y, int w, int h) {
        fillRect_rect.setX((short) (x + this.translateX));
        fillRect_rect.setY((short) (y + this.translateY));
        fillRect_rect.setW(w);
        fillRect_rect.setH(h);

        //long c = SDL.SDL_MapRGB(format, (short) currentColor.r, (short) currentColor.g, (short) currentColor.b);
        SDL.SDL_FillRect(surface, fillRect_rect, current_sdlcolor);
    }


    public void drawImage(SImage image, int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh) {
        imgsrc_rect.setX((short) sx);
        imgsrc_rect.setY((short) sy);
        imgsrc_rect.setW(sw);
        imgsrc_rect.setH(sh);
        imgdst_rect.setX((short) (dx+this.translateX));
        imgdst_rect.setY((short) (dy+this.translateY));
        imgdst_rect.setW(dw);
        imgdst_rect.setH(dh);

        SDL.SDL_UpperBlit(image._sdlimage, imgsrc_rect, surface, imgdst_rect);
    }

    public void drawImage(SImage image, int x, int y) {
        drawImage(image._sdlimage,x,y);
    }

    protected void drawImage(SDL_Surface image, int x, int y) {
        imgsrc_rect.setX((short) 0);
        imgsrc_rect.setY((short) 0);
        imgsrc_rect.setW(image.getW());
        imgsrc_rect.setH(image.getH());
        imgdst_rect.setX((short) (x+this.translateX));
        imgdst_rect.setY((short) (y+this.translateY));
        imgdst_rect.setW(0);
        imgdst_rect.setH(0);
        SDL.SDL_UpperBlit(image,imgsrc_rect,surface,imgdst_rect);
    }

    public void drawBuffer(SBuffer buffer, int x, int y) {
        imgsrc_rect.setX((short) 0);
        imgsrc_rect.setY((short) 0);
        imgsrc_rect.setW(buffer._surface.getW());
        imgsrc_rect.setH(buffer._surface.getH());
        imgdst_rect.setX((short) x);
        imgdst_rect.setY((short) y);
        imgdst_rect.setW(0);
        imgdst_rect.setH(0);
        SDL.SDL_UpperBlit(buffer._surface,imgsrc_rect,surface,imgdst_rect);
    }

    public TextMetrics measureString(SFont font, String s) {
        //SDL.TTF_SetFontHinting(font._sdlfont, SDL.TTF_HINTING_NORMAL);
        int[] minx = {0};
        int[] maxx = {0};
        int[] miny = {0};
        int[] maxy = {0};
        int[] advance = {0};
        TextMetrics tm = new TextMetrics();
        int totalAdvance = 0;
        for (int i = 0; i < s.length(); i++) {
            int ret = SDL.TTF_GlyphMetrics(font._sdlfont, s.charAt(i)
                    , minx
                    , maxx
                    , miny
                    , maxy
                    , advance
            );
            if(i==0) tm.minx = minx[0];
            totalAdvance += advance[0];
        }

        tm.maxx = totalAdvance;
        return tm;
    }

    public void drawString(SFont font, String s, int dx, int dy) {

        SDL_Color fg = new SDL_Color();
        fg.setR((short) currentColor.r);
        fg.setG((short) currentColor.g);
        fg.setB((short) currentColor.b);
        fg.setUnused((short) 0);

        SDL_Color bg = new SDL_Color();
        bg.setR((short) 0xFF);
        bg.setG((short) 0xFF);
        bg.setB((short) 0xFF);
        bg.setUnused((short) 0xFF);

        //SDL.TTF_SetFontHinting(font._sdlfont, SDL.TTF_HINTING_NORMAL);

        int x = 0;
        int[] minx = {0};
        int[] maxx = {0};
        int[] miny = {0};
        int[] maxy = {0};
        int[] advance = {0};
        for (int i = 0; i < s.length(); i++) {
            //SDL_Surface glyph_surface = SDL.TTF_RenderGlyph_Shaded(font._sdlfont, s.charAt(i), fg, bg);
            SDL_Surface glyph_surface = SDL.TTF_RenderGlyph_Blended(font._sdlfont, s.charAt(i), fg);
            int ret = SDL.TTF_GlyphMetrics(font._sdlfont, s.charAt(i)
                    , minx
                    , maxx
                    , miny
                    , maxy
                    , advance
            );
            fontsrc_rect.setX((short) 0);
            fontsrc_rect.setY((short) 0);
            fontsrc_rect.setW(glyph_surface.getW());
            fontsrc_rect.setH(glyph_surface.getH());

            fontdst_rect.setX((short) (dx + x + translateX));
            fontdst_rect.setY((short) (dy - maxy[0] + translateY));
            fontdst_rect.setW(0);
            fontdst_rect.setH(0);
            SDL.SDL_UpperBlit(glyph_surface, fontsrc_rect, surface, fontdst_rect);
            x += advance[0];
        }
    }

    public void draw9Slice(SImage image
            , int left, int right
            , int top, int bottom
            , int destX, int destY
            , int destW, int destH) {


        //draw parts of image
        int yh = image.getHeight()-top-bottom;

        drawRow(image, destX, destY, destW,
                left, right, 0, top, 0);

        //middle
        //Util.p("top = " + top + " desth = " + destH + " bottom = " + bottom + " yh = " + yh);
        for (int j = top; j <= destH-bottom-yh; j += yh) {
            //Util.p("drawing once");
            drawRow(image, destX, destY, destW,
                left, right, top, yh, j);
        }

        //center end
        int ygap = (destH-top-bottom) % yh;
        drawRow(image, destX, destY, destW,
                left, right, top, ygap, destH-bottom-ygap
                );

        drawRow(image, destX, destY, destW,
                left, right, image.getHeight()-bottom, bottom, destH-bottom
        );
    }

    private void drawRow(SImage image, int destX, int destY, int destW,
                         int left, int right, int sy, int sh, int dy) {
        int xw = image.getWidth()-left-right;
        // left
        drawImage(image,
                0, sy, left, sh,
                destX+0, destY+dy, left, sh);
        // center

        for (int i = left; i < destW-right-xw; i += xw) {
            drawImage(image,
                    left, sy, image.getWidth()-right-left, sh,
                    destX+i, destY+dy, xw, sh);
        }
        //center end
        int xgap = (destW-left-right) % xw;
        drawImage(image,
                left, sy, xgap, sh,
                destX+destW-right-xgap, destY+dy, xgap, sh
            );
        // right
        drawImage(image,
                image.getWidth()-right, sy, right, sh,
                destX+destW-right, destY+dy, right, sh);
    }

    private void drawRow2(SImage image, int destX, int destY, int destW,
                          int left, int right, int sy, int sh, int dy) {
        int xw = image.getWidth()-left-right;
        // left
        drawImage(image,
                0, sy, left, sh,
                destX+0, destY+dy, left, sh);
        // center
        for (int i = left; i < destW-right-xw; i += xw) {
            drawImage(image,
                    left, sy, xw, sh,
                    destX+i, destY+dy, xw, sh);
        }
        // right
        drawImage(image,
                image.getWidth()-right, sy, right, sh,
                destX+destW-right, destY+dy, right, sh);

    }

    public void translate(int x, int y) {
        this.translateX += x;
        this.translateY += y;
    }

    public SBuffer createBuffer(int width, int height) {
        SDL_Surface surface2 = SDL.SDL_CreateRGBSurface(SDLConstants.SDL_SWSURFACE, width, height, format.getBitsPerPixel(), format.getRmask(), format.getGmask(), format.getBmask(), format.getAmask());
        return new SBuffer(surface2, width, height);
    }

    public Object getNative() {
        return this.surface;
    }


    public void setPaint(SPaint sPaint) {
        this.currentPaint = sPaint;
        if(sPaint instanceof SColor) {
            currentColor = (SColor) sPaint;
            this.current_sdlcolor = SDL.SDL_MapRGB(format, (short) currentColor.r, (short) currentColor.g, (short) currentColor.b);
        }
    }

    public Bounds getClipRect() {
        return clipRect;
    }

    public void setClipRect(Bounds bounds) {
        SDL_Rect r2 = new SDL_Rect();
        r2.setX((short) bounds.x);
        r2.setY((short) bounds.y);
        r2.setW(bounds.width);
        r2.setH(bounds.height);
        SDL.SDL_SetClipRect(surface,r2);
        clipRect = bounds;
    }


    public static class TextMetrics {
        public int minx;
        public int maxx;
    }


    public abstract void drawRect(int x, int y, int width, int height);
    public abstract void drawVLine(int x, int y, int height);
    public abstract void drawHLine(int x, int y, int width);
    public abstract void drawLine(int x1, int y1, int x2, int y2);
    public abstract void drawCircle(GFX gfx, int cx, int cy, int radius);
    public abstract void drawEllipse(int x, int y, int width, int height);
    public abstract void fillEllipse(int x, int y, int width, int height);
    public abstract void drawRoundRect(int x, int y, int width, int height, int radius);
    public abstract void fillRoundRect(int x, int y, int width, int height, int radius);
    public abstract void drawWuPixel(double x, double y);
}

